package com.bsj.power.pls.queue.service.impl.handle;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.bsj.consumerQ.function.HandleRunT;
import com.bsj.consumerQ.method.QueueAndRunT;
import com.bsj.power.common.config.cached.BindCardCached;
import com.bsj.power.common.config.cached.LocationDeviceCached;
import com.bsj.power.common.config.cached.RedisCached;
import com.bsj.power.common.config.cached.WorkPersonnelCached;
import com.bsj.power.common.config.redis.RedisConstant;
import com.bsj.power.common.constant.NumericalConstants;
import com.bsj.power.common.def.dto.cardReport.BindCardDTO;
import com.bsj.power.common.def.entity.job.WorkPersonnel;
import com.bsj.power.common.def.entity.locationDevice.LocationDevice;
import com.bsj.power.common.def.entity.personnel.Personnel;
import com.bsj.power.common.def.mq.sdk.face.PersonInfo;
import com.bsj.power.common.mapper.PersonnelMapper;
import com.bsj.power.common.mapper.WorkPersonnelMapper;
import com.bsj.power.common.netty.StockInfo;
import com.bsj.power.common.util.DateUtils;
import com.bsj.power.common.util.ExceptionUtil;
import com.bsj.power.pls.cache.BindCardMachineCache;
import com.bsj.power.pls.cache.PanelCache;
import com.bsj.power.pls.netty.CTInstructUtils;
import com.bsj.power.pls.netty.CachedChannelMap;
import com.bsj.power.pls.service.LocationDeviceService;
import com.hikvision.artemis.sdk.ArtemisHttpUtil;
import com.hikvision.artemis.sdk.config.ArtemisConfig;
import com.hikvision.artemis.sdk.constant.ContentType;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.iot.mqtt.core.server.MqttServer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author LiJiaXin
 * @version 1.0.0
 * @description HumanFaceQueue
 * @time 2024/9/21 10:58
 */
@Slf4j
@Service
public class QueueHumanFaceHandle implements HandleRunT<PersonInfo> {

    @Value("${hiKv.host}")
    private String host;

    @Value("${hiKv.appKey}")
    private String appKey;

    @Value("${hiKv.appSecret}")
    private String appSecret;

    /**
     * url格式：https://{hostname}:{port}/artemis/{uri}。
     */
    private final String ARTEMIS_PATH = "/artemis";

//    /**
//     * 面板机与绑卡机的绑定关系MAP
//     * KEY面板机资源编号
//     * VALUE 绑卡机设备ID
//     */
//    public static Map<String, String> BIND_RELATION_MAP = new HashMap<>();
//    /**
//     * 面板机资源编号集
//     */
//    public static List<String> SRC_INDEX_LIST = new ArrayList<>();


    @Resource
    private PersonnelMapper personnelMapper;

    @Resource
    private WorkPersonnelMapper workPersonnelMapper;

    @Autowired
    private BindCardCached bindCardCached;

//    @Autowired
//    private LocationDeviceService locationDeviceService;

    @Autowired
    private MqttServer mqttServer;

    @Autowired
    private RedisCached redisCached;

    @Autowired
    private WorkPersonnelCached workPersonnelCached;

    @Autowired
    private LocationDeviceCached locationDeviceCached;

    @Override
    public void doRun(List<PersonInfo> list) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        for (PersonInfo personInfo : list) {
            if (personInfo == null) {
                continue;
            }
            try {
                paramHandle(personInfo);
            } catch (Exception e) {
                log.error("人脸信息处理失败,异常信息：{}，人员信息：{}", ExceptionUtil.getStackStr(e), personInfo);
            }
        }
    }

    /**
     * 参数处理
     *
     * @param personInfo
     * @return void
     * @author ljx
     * @time 2024/9/19 21:51
     */
    private void paramHandle(PersonInfo personInfo) {
        log.info("当前人脸识别人员信息：{}", personInfo);
        String srcIndex = personInfo.getSrcIndex();
        //人员编号（人员id）
        String extEventPersonNo = personInfo.getExtEventPersonNo();
        if (!PanelCache.SRC_INDEX_LIST.contains(srcIndex)) {
            log.info("面板机编号不存在：{}", srcIndex);
            return;
        }
        if (StringUtils.isBlank(extEventPersonNo)) {
            log.info("人员编号为空");
            return;
        }
        //根据srcIndex确定是哪个面板机上报的事件，根据与绑卡机的组合方式来确定控制哪个绑卡机弹哪张卡
        String deviceId = PanelCache.getRelation(srcIndex);
        if (StringUtils.isBlank(deviceId)) {
            log.info("没找到对应的绑卡机，面板机资源编号：{}", srcIndex);
            return;
        }
        String clientId = CachedChannelMap.getClientId(deviceId);
        if (StringUtils.isBlank(clientId)) {
            log.info("人脸识别时绑卡机设备离线：{}", deviceId);
            return;
        }
        //是否绑过卡
        String empNo = personnelMapper.selectEmpNoByExtEventPersonNo(extEventPersonNo);
        String temporaryEmpNo = workPersonnelMapper.selectTemporaryEmpNoByExtEventPersonNo(extEventPersonNo);
        BindCardDTO bindCardDTOOne = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_EMP_NO_KEY + empNo);
        BindCardDTO bindCardDTOTwo = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_EMP_NO_KEY + temporaryEmpNo);
        if (bindCardDTOOne != null || bindCardDTOTwo != null) {
            log.info("该人员已绑卡，负责人工号：{}，作业人员工号：{},姓名：{}", empNo, temporaryEmpNo, personInfo.getName());
            return;
        }
        //面板机人员编号缓存，防止多次扫脸多次弹卡
        String str = redisCached.get(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo);
        if (StringUtils.isNotBlank(str)) {
            log.info("已存在人员编号弹卡待处理，人员编号：{}，姓名：{}", str, personInfo.getName());
            return;
        }
        StockInfo stockInfo = getStockInfo(deviceId);
        if (stockInfo == null) {
            log.info("无多余的卡可弹出，绑卡机设备ID：{}", deviceId);
            return;
        }
        //人员编号缓存，防止多次弹卡，存在平台手动绑卡时该人员当时无人员编号信息，所以扫脸时允许弹卡一次但不进行具体的绑卡操作，10秒过期
        redisCached.set(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo, extEventPersonNo, 10);
//                redisCached.set(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo, extEventPersonNo);
        log.info("人员编号新缓存：{}", redisCached.get(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo));
        //缓存设备号与人员的关系
        Integer serialNum = stockInfo.getSerialNum();
        boolean flag = redisCached.set(RedisConstant.DEVICE_NAME_EXT_EVENT_PERSON_NO_BIND_KEY + stockInfo.getUwbNo(), personInfo);
        if (flag) {
            mqttServer.publish(clientId, CTInstructUtils.getTopicSend(deviceId)
                    , CTInstructUtils.assembleUwbPopCmd(deviceId, serialNum));
            log.info("弹卡指令已下发，本次弹卡扫脸人员编号：{}，姓名：{},绑卡机编号：{}，面板机编号：{}，仓位信息：{}", extEventPersonNo, personInfo.getName(), deviceId, srcIndex, JSONObject.toJSONString(stockInfo));
            //将该仓位置空
            BindCardMachineCache.putStockInfo(deviceId, new StockInfo(serialNum));
        } else {
            log.info("设备号与人员编号关系缓存失败");
        }
    }

//    /**
//     * 参数处理
//     *
//     * @param jsonObject
//     * @return void
//     * @author ljx
//     * @time 2024/9/19 21:51
//     */
//    private void paramHandle(JSONObject jsonObject) {
//        //方法名，用于标识报文用途，事件固定OnEventNotify
//        String method = jsonObject.getString("method");
//        //事件参数信息
//        JSONObject params = jsonObject.getJSONObject("params");
//        if (StringUtils.isBlank(method) || !method.equals("OnEventNotify") || params == null) {
//            return;
//        }
//        //事件类别，人脸事件为event_face_recognition
//        String ability = params.getString("ability");
//        if (StringUtils.isNotBlank(ability) && ability.equals("event_acs")) {
//            //事件信息
//            JSONArray eventArray = params.getJSONArray("events");
//            if (CollectionUtils.isEmpty(eventArray)) {
//                return;
//            }
//            List<JSONObject> eventtList = eventArray.toJavaList(JSONObject.class);
//            if (CollectionUtils.isEmpty(eventtList)) {
//                return;
//            }
//            for (JSONObject event : eventtList) {
//                //事件详情
//                JSONObject data = event.getJSONObject("data");
//                //事件源编号，物理设备是资源编号（区分是哪个面板机上报的事件）
//                String srcIndex = event.getString("srcIndex");
//                //事件源类型，核电人脸比对事件源类型为faceGroup
//                String srcType = event.getString("srcType");
////                //事件源名称（TODO 可能是面本机名称，待确认）
////                String srcName = event.getString("srcName");
//                //事件类型，门禁事件类型为196893
//                Integer eventType = event.getInteger("eventType");
////                //事件发生时间（设备时间）
////                String happenTime = event.getString("happenTime");
//                if (!SRC_INDEX_LIST.contains(srcIndex)) {
//                    continue;
//                }
//                if (!srcType.equals("door")) {
//                    continue;
//                }
//                if (data == null || eventType != 196893) {
//                    continue;
//                }
//                //事件类型代码
//                Integer extEventCode = data.getInteger("ExtEventCode");
//                if (extEventCode == null || extEventCode != 196893) {
//                    continue;
//                }
//                //人员编号（人员id）
//                String extEventPersonNo = data.getString("ExtEventPersonNo");
//                if (StringUtils.isBlank(extEventPersonNo)) {
//                    continue;
//                }
//                //根据srcIndex确定是哪个面板机上报的事件，根据与绑卡机的组合方式来确定控制哪个绑卡机弹哪张卡
//                String deviceId = BIND_RELATION_MAP.get(srcIndex);
//                if (StringUtils.isBlank(deviceId)) {
//                    log.info("没找到对应的绑卡机，面板机资源编号：{}", srcIndex);
//                    continue;
//                }
//                String clientId = CachedChannelMap.getClientId(deviceId);
//                if (StringUtils.isBlank(clientId)) {
//                    log.info("人脸识别时绑卡机设备离线：{}", deviceId);
//                    continue;
//                }
//                //是否绑过卡
//                String empNo = personnelMapper.selectEmpNoByExtEventPersonNo(extEventPersonNo);
//                String temporaryEmpNo = workPersonnelMapper.selectTemporaryEmpNoByExtEventPersonNo(extEventPersonNo);
//                BindCardDTO bindCardDTOOne = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_EMP_NO_KEY + empNo);
//                BindCardDTO bindCardDTOTwo = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_EMP_NO_KEY + temporaryEmpNo);
//                if (bindCardDTOOne != null || bindCardDTOTwo != null) {
//                    log.info("该人员已绑卡，负责人工号：{}，作业人员工号：{}", empNo, temporaryEmpNo);
//                    continue;
//                }
//                StockInfo stockInfo = getStockInfo(deviceId);
//                if (stockInfo == null) {
//                    log.info("无多余的卡可弹出，绑卡机设备ID：{}", deviceId);
//                    continue;
//                }
//                //安防平台人员编号缓存，防止多次扫脸多次弹卡
//                String str = redisCached.get(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo);
//                if (StringUtils.isNotBlank(str)) {
//                    log.info("已存在人员编号弹卡待处理：{}", str);
//                    continue;
//                }
//                //10秒过期
//                redisCached.set(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo, extEventPersonNo, 10);
////                redisCached.set(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo, extEventPersonNo);
//                log.info("人员编号新缓存：{}", redisCached.get(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo));
//                //缓存设备号与人员编号的关系
//                Integer serialNum = stockInfo.getSerialNum();
//                boolean flag = redisCached.set(RedisConstant.DEVICE_NAME_EXT_EVENT_PERSON_NO_BIND_KEY + stockInfo.getUwbNo(), extEventPersonNo);
//                if (flag) {
//                    mqttServer.publish(clientId, CTInstructUtils.getTopicSend(deviceId)
//                            , CTInstructUtils.assembleUwbPopCmd(deviceId, serialNum));
//                    log.info("弹卡指令已下发，本次弹卡扫脸人员编号：{}，绑卡机编号：{}，面板机编号：{}，仓位信息：{}", extEventPersonNo, deviceId, srcIndex, JSONObject.toJSONString(stockInfo));
//                    //将该仓位置空
//                    BindCardMachineCache.putStockInfo(deviceId, new StockInfo(serialNum));
//                    return;
//                } else {
//                    log.info("设备号与人员编号关系缓存失败");
//                }
//            }
//        }
//    }

//    /**
//     * 参数处理
//     *
//     * @param jsonObject
//     * @return void
//     * @author ljx
//     * @time 2024/9/19 21:51
//     */
//    private void paramHandle(JSONObject jsonObject) {
//        //方法名，用于标识报文用途，事件固定OnEventNotify
//        String method = jsonObject.getString("method");
//        //事件参数信息
//        JSONObject params = jsonObject.getJSONObject("params");
//        if (StringUtils.isBlank(method) || !method.equals("OnEventNotify") || params == null) {
//            return;
//        }
//        //事件类别，人脸事件为event_face_recognition
//        String ability = params.getString("ability");
//        if (StringUtils.isNotBlank(ability) && ability.equals("event_acs")) {
//            //事件信息
//            JSONArray eventArray = params.getJSONArray("events");
//            if (CollectionUtils.isEmpty(eventArray)) {
//                return;
//            }
//            List<JSONObject> eventtList = eventArray.toJavaList(JSONObject.class);
//            if (CollectionUtils.isEmpty(eventtList)) {
//                return;
//            }
//            for (JSONObject event : eventtList) {
//                //事件详情
//                JSONObject data = event.getJSONObject("data");
//                //事件源编号，物理设备是资源编号（区分是哪个面板机上报的事件）
//                String srcIndex = event.getString("srcIndex");
//                //事件源类型，核电人脸比对事件源类型为faceGroup
//                String srcType = event.getString("srcType");
////                //事件源名称（TODO 可能是面本机名称，待确认）
////                String srcName = event.getString("srcName");
//                //事件类型，门禁事件类型为196893
//                Integer eventType = event.getInteger("eventType");
////                //事件发生时间（设备时间）
////                String happenTime = event.getString("happenTime");
//                if (!SRC_INDEX_LIST.contains(srcIndex)) {
//                    continue;
//                }
//                if (!srcType.equals("door")) {
//                    continue;
//                }
//                if (data == null || eventType != 196893) {
//                    continue;
//                }
//                //事件类型代码
//                Integer extEventCode = data.getInteger("ExtEventCode");
//                if (extEventCode == null || extEventCode != 196893) {
//                    continue;
//                }
//                //人员编号（人员id）
//                String extEventPersonNo = data.getString("ExtEventPersonNo");
//                if (StringUtils.isBlank(extEventPersonNo)) {
//                    continue;
//                }
//                //添加人员编号缓存，过期时间设置30秒，防止多次扫脸弹多张卡
//                String str = redisCached.get(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo);
//                if (StringUtils.isNotBlank(str)) {
//                    log.info("已存在人员编号弹卡待处理：{}", str);
//                    continue;
//                }
//                redisCached.set(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo, extEventPersonNo, 30);
//                log.info("人员编号新缓存：{}", redisCached.get(RedisConstant.EXT_EVENT_PERSON_NO_KEY + extEventPersonNo));
//
//
//
//                //根据人员编号查询负责人信息与作业人员信息，看平台内是否有对应的人
//                Personnel personnel = personnelMapper.selectOne(Wrappers.<Personnel>lambdaQuery().eq(Personnel::getExtEventPersonNo, extEventPersonNo));
//                WorkPersonnel workPersonnel = workPersonnelMapper.selectOne(Wrappers.<WorkPersonnel>lambdaQuery().eq(WorkPersonnel::getIdCardNo, extEventPersonNo));
//                //如果没有这个人员则调用第三方api查询人员信息，根据身份证号判断数据库是否有这个人，如果有则修改人员id，如果没有添加这个人员信息
//                if (personnel == null && workPersonnel == null) {
//                    WorkPersonnel newWorkPersonnel = getPersonInfoIdCardNo(extEventPersonNo);
//                    if (newWorkPersonnel == null || StringUtils.isBlank(newWorkPersonnel.getIdCardNo())) {
//                        log.info("综合安防平台未查询到对应的人员信息或该人员身份证不存在，人员编号为：{}", extEventPersonNo);
//                        continue;
//                    }
//                    //添加作业人员信息或填充人员编号，此方法执行过会三个信息至少有一个不为空
//                    insertOrUpdateWorkPersonnel(newWorkPersonnel, personnel, workPersonnel);
//                    if (personnel == null && workPersonnel == null) {
//                        workPersonnel = newWorkPersonnel;
//                    }
//                }
//                //本地测试指定人员
////                String idCardNo = "430584199509078541";
//                //工号
//                String empNo;
//                //姓名
//                String name;
//                //身份证号
//                String idCardNo;
//                //人员类型
//                Integer classify;
//                if (personnel != null) {
//                    empNo = personnel.getEmpNo();
//                    name = personnel.getName();
//                    idCardNo = personnel.getIdCardNo();
//                    classify = NumericalConstants.ZERO;
//                } else {
//                    empNo = workPersonnel.getTemporaryEmpNo();
//                    name = workPersonnel.getName();
//                    idCardNo = workPersonnel.getIdCardNo();
//                    classify = NumericalConstants.ONE;
//                }
//                BindCardDTO oldBindCardDTO = bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_EMP_NO_KEY + empNo);
//                //人脸识别只用来绑卡，还卡是绑卡机设备主动上报，无需人脸识别
//                if (oldBindCardDTO == null) {
//                    //TODO 下发指令控制弹卡
//                    //根据srcIndex确定是哪个面板机上报的事件，根据与绑卡机的组合方式来确定控制哪个绑卡机弹哪张卡
//                    String deviceId = BIND_RELATION_MAP.get(srcIndex);
//                    if (StringUtils.isBlank(deviceId)) {
//                        log.warn("没找到对应的绑卡机，面板机资源编号：{}", srcIndex);
//                        continue;
//                    }
//                    String clientId = CachedChannelMap.getClientId(deviceId);
//                    if (StringUtils.isBlank(clientId)) {
//                        log.warn("设备离线：{}", deviceId);
//                        continue;
//                    }
//                    StockInfo stockInfo = getStockInfo(deviceId);
//                    if (stockInfo == null) {
//                        log.warn("无多余的卡可弹出，绑卡机设备ID：{}", deviceId);
//                        continue;
//                    }
//                    Integer serialNum = stockInfo.getSerialNum();
//                    //绑卡操作
//                    BindCardDTO bindCardDTO = new BindCardDTO(stockInfo.getUwbNo(), classify, name, empNo, idCardNo, NumericalConstants.ONE,extEventPersonNo);
//                    //以绑卡机设备ID为大KEY，仓位号为小KEY临时存储绑卡信息与仓位信息
//                    redisCached.hset(RedisConstant.TEMP_BIND_CARD_REDIS_KEY + deviceId, serialNum + "", JSON.toJSONString(bindCardDTO));
//                    redisCached.hset(RedisConstant.TEMP_STOCK_REDIS_KEY + deviceId, serialNum + "", JSON.toJSONString(stockInfo));
//                    mqttServer.publish(clientId, CTInstructUtils.getTopicSend(deviceId)
//                            , CTInstructUtils.assembleUwbPopCmd(deviceId, serialNum));
//                    //执行一次绑卡或退卡操作后本次人脸比对事件结束
//                } else {
//                    log.info(name + "已绑卡，人脸识别智慧绑卡失败");
//                }
//                return;
//            }
//        }
//    }

    /**
     * 添加作业人员或填充人员编号
     *
     * @param newWorkPersonnel
     * @return void
     * @author ljx
     * @time 2024/10/24 14:58
     */
    private void insertOrUpdateWorkPersonnel(WorkPersonnel newWorkPersonnel, Personnel personnel, WorkPersonnel workPersonnel) {
        boolean flag = false;
        String idCardNo = newWorkPersonnel.getIdCardNo();
        String extEventPersonNo = newWorkPersonnel.getExtEventPersonNo();
        //根据身份证号查询是否有这个人
        personnel = personnelMapper.selectOne(Wrappers.<Personnel>lambdaQuery().eq(Personnel::getIdCardNo, idCardNo));
        workPersonnel = workPersonnelMapper.selectOne(Wrappers.<WorkPersonnel>lambdaQuery().eq(WorkPersonnel::getIdCardNo, idCardNo));
        //新加作业人员
        if (personnel == null && workPersonnel == null) {
            //给人员信息生成一个唯一工号
            newWorkPersonnel.setTemporaryEmpNo(IdUtil.objectId());
            //根据身份证号计算年龄
            String year = idCardNo.substring(6, 10);
            String month = idCardNo.substring(10, 12);
            String day = idCardNo.substring(12, 14);
            String dateOfBirth = year + "-" + month + "-" + day + " 00:00:00";
            newWorkPersonnel.setAge(DateUtils.getAgeByDate(dateOfBirth));
            flag = workPersonnelMapper.insert(newWorkPersonnel) > NumericalConstants.ZERO;
            if (flag) {
                workPersonnelCached.setWorkPersonnelInfo(newWorkPersonnel);
                log.info("人脸识别同步作业人员信息成功，人员数据：{}", newWorkPersonnel);
            } else {
                log.info("人脸识别同步作业人员信息失败，人员数据：{}", newWorkPersonnel);
            }
        } else {
            //填充人员编号进数据库，但不填充进缓存
            if (personnel != null) {
                flag = personnelMapper.updateById(new Personnel(personnel.getPersonnelId(), extEventPersonNo)) > NumericalConstants.ZERO;
                if (flag) {
                    log.info("人脸识别修改负责人信息成功，人员数据：{}", newWorkPersonnel);
                } else {
                    log.info("人脸识别修改负责人信息失败，人员数据：{}", newWorkPersonnel);
                }
            } else {
                flag = workPersonnelMapper.updateById(new WorkPersonnel(workPersonnel.getWorkPersonnelId(), extEventPersonNo)) > NumericalConstants.ZERO;
                if (flag) {
                    log.info("人脸识别修改作业人员信息成功，人员数据：{}", newWorkPersonnel);
                } else {
                    log.info("人脸识别修改作业人员信息成功，人员数据：{}", newWorkPersonnel);
                }
            }
        }
    }

    /**
     * 返回可弹卡的仓位信息
     *
     * @param deviceId
     * @return com.bsj.power.common.netty.StockInfo
     * @author ljx
     * @time 2024/9/26 15:58
     */
    private StockInfo getStockInfo(String deviceId) {
        StockInfo stockInfo = null;
        List<StockInfo> stockInfoList = BindCardMachineCache.getStockInfoList(deviceId);
        log.info("返回可弹卡的仓位信息方法信息集：{}", stockInfoList);
        if (!CollectionUtils.isEmpty(stockInfoList)) {
            List<StockInfo> permitUseStockInfoList = stockInfoList.stream().filter(item -> filterStockInfo(item))
                    .sorted(Comparator.comparing(StockInfo::getUwbPower).reversed()).collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(permitUseStockInfoList)) {
                log.info("可弹卡的仓位集：{}", permitUseStockInfoList);
                stockInfo = permitUseStockInfoList.get(NumericalConstants.ZERO);
            }
        }
        return stockInfo;
    }

    /**
     * 筛选可弹出的卡
     *
     * @param stockInfo
     * @return boolean
     * @author ljx
     * @time 2024/12/23 10:26
     */
    private boolean filterStockInfo(StockInfo stockInfo) {
        Integer state = stockInfo.getState();
        if (state == null || !state.equals(NumericalConstants.ONE)) {
            return false;
        }
        String uwbNo = stockInfo.getUwbNo();
        if (StringUtils.isBlank(uwbNo)) {
            return false;
        }
        LocationDevice locationDevice = locationDeviceCached.hgetLocationDeviceInfo(uwbNo);
        if (locationDevice == null) {
            return false;
        }
        if (locationDevice.getIsLockIn() != null && locationDevice.getIsLockIn().equals(NumericalConstants.ONE)) {
            return false;
        }
        if (bindCardCached.hgetBindCardInfo(RedisConstant.BIND_CARD_REDIS_DEVICE_NAME_KEY + uwbNo) != null) {
            return false;
        }
        return true;
    }

    /**
     * 根据人员id获取人员身份证号
     * 请求海康“根据人员唯一字段获取人员详细信息”API
     *
     * @param extEventPersonNo
     * @return java.lang.String
     * @author ljx
     * @time 2024/9/25 11:43
     */
    private WorkPersonnel getPersonInfoIdCardNo(String extEventPersonNo) {
        ArtemisConfig.host = host;
        ArtemisConfig.appKey = appKey;
        ArtemisConfig.appSecret = appSecret;
        // 调用接口地址
        final String url = "/api/resource/v1/person/condition/personInfo";
        final String httpStr = "https://";
        Map<String, String> path = Map.of(httpStr, ARTEMIS_PATH + url);

        //根据人员唯一字段获取人员详细信息请求参数
        String[] array = {extEventPersonNo};
        JSONObject jsonBody = new JSONObject();
        jsonBody.put("paramName", "personId");
        jsonBody.put("paramValue", array);
        String body = jsonBody.toString();
        String result = ArtemisHttpUtil.doPostStringArtemis(path, body, null, null, ContentType.CONTENT_TYPE_JSON);
        if (StringUtils.isNotBlank(result)) {
            JSONObject jsonObject = JSONObject.parseObject(result);
            Integer code = jsonObject.getInteger("code");
            if (code != null && code.equals(NumericalConstants.ZERO)) {
                log.info("请求根据人员唯一字段获取人员详细信息成功，请求地址：{}，请求参数{}，返回内容：{}", JSONObject.toJSONString(path), body, result);
                JSONObject data = jsonObject.getJSONObject("data");
                if (data == null) {
                    return null;
                }
                JSONArray jsonArray = data.getJSONArray("list");
                if (CollectionUtils.isEmpty(jsonArray)) {
                    return null;
                }
                List<JSONObject> jsonObjects = jsonArray.toJavaList(JSONObject.class);
                if (CollectionUtils.isEmpty(jsonObjects)) {
                    return null;
                }
                //人员信息
                JSONObject personInfo = jsonObjects.get(NumericalConstants.ZERO);
                //证件类型 111代表身份证
                Integer certificateType = personInfo.getInteger("certificateType");
                //证件号码
                String certificateNo = personInfo.getString("certificateNo");
                if (certificateType == null || certificateType != 111 || StringUtils.isBlank(certificateNo)) {
                    return null;
                }
                //姓名
                String personName = personInfo.getString("personName");
                //电话
                String phoneNo = personInfo.getString("phoneNo");
                WorkPersonnel workPersonnel = new WorkPersonnel(personName, phoneNo, certificateNo, extEventPersonNo);
                return workPersonnel;
            } else {
                log.info("请求根据人员唯一字段获取人员详细信息失败，请求地址：{}，请求参数{}，返回内容：{}", JSONObject.toJSONString(path), body, result);
            }
        } else {
            log.info("请求根据人员唯一字段获取人员详细信息失败，返回无结果，请求地址：{}，请求参数{}", JSONObject.toJSONString(path), body);
        }
        return null;
    }
}
